package up

import (
	"bufio"
	"bytes"
	"flag"
	"fmt"
	"github.com/gookit/color"
	"io/fs"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"time"
)

func RunUpdate() {
	var targetDir string
	var fileName string
	var count int
	var err error
	getwd, _ := os.Getwd()
	flag.StringVar(&targetDir, "t", "", "目标文件夹")
	flag.StringVar(&fileName, "name", "go.mod", "go.mod")
	flag.IntVar(&count, "c", 5, "chan")
	flag.Parse()

	isAbs := filepath.IsAbs(targetDir)
	if !isAbs {
		targetDir, err = filepath.Abs(filepath.Join(getwd, targetDir))
		if err != nil {
			panic(err)
		}
	}

	stat, err := os.Stat(targetDir)
	if err != nil {
		panic(err)
	}
	begin := targetDir
	if !stat.IsDir() {
		begin = filepath.Dir(targetDir)
	}
	fmt.Println("abs", targetDir)
	fmt.Println("begin", begin)

	var tarPax []string
	err = filepath.WalkDir(begin, func(path string, d fs.DirEntry, err error) error {
		if filepath.Base(path) != "go.mod" {
			return nil
		}
		tarPax = append(tarPax, path)
		return nil
	})
	if err != nil {
		panic(err)
	}
	var wg sync.WaitGroup
	for _, pax := range tarPax {
		wg.Add(1)
		go func() {
			defer wg.Done()
			color.Yellowln("==========", pax)
			packages, err := readFile(pax)
			if err != nil {
				return
			}
			cmdRun(filepath.Dir(pax), packages, count)
		}()
	}
	wg.Wait()
}
func readFile(filePATH string) (map[string]any, error) {
	file, err := os.Open(filePATH)
	if err != nil {
		return nil, err
	}
	defer file.Close()
	requireRegexp := regexp.MustCompile(`^\S* `)
	replaceRegexp := regexp.MustCompile(` v.+`)
	scanner := bufio.NewScanner(file)
	scanner.Split(bufio.ScanLines)
	var packageNames = make(map[string]any)
	for scanner.Scan() {
		text := scanner.Text()
		if !replaceRegexp.MatchString(text) {
			continue
		}
		packageName := replaceRegexp.ReplaceAllString(text, "")
		packageName = strings.TrimSpace(requireRegexp.ReplaceAllString(packageName, ""))
		packageNames[packageName] = nil
		//packageNames = append(packageNames, packageName)
	}
	return packageNames, nil
}
func cmdRun(workDir string, packages map[string]any, count int) {
	var wg sync.WaitGroup
	if count < 1 {
		count = 3
	}
	ints := make(chan int, count)
	for s := range packages {
		wg.Add(1)
		ints <- 1
		go func() {
			defer func() {
				wg.Done()
				<-ints
			}()
			cmd := exec.Command("go", "get", s)
			cmd.Dir = workDir
			var stdout, stderr bytes.Buffer
			cmd.Stdout = &stdout // 标准输出
			cmd.Stderr = &stderr // 标准错误
			color.Greenf("%v:%v ", time.Now().Format(time.DateTime), workDir)
			color.Redln(cmd.String())
			err := cmd.Run()
			if err != nil {
				color.Redln("err", err.Error())
				return
			}
			if len(stdout.Bytes()) > 0 {
				color.Grayln("stdout", string(stdout.Bytes()))
			}
			if len(stderr.Bytes()) > 0 {
				color.Magentaln("stderr", string(stderr.Bytes()))
			}
		}()
	}
	wg.Wait()
	command := exec.Command("go", "mod", "tidy")
	command.Run()
}
